# -*- coding: utf-8 -*-
# Copyright under  the latest Apache License 2.0
import urlparse, base64, logging
from uuid import uuid4

from django.http import HttpResponse
from django.http import HttpResponseRedirect

import oauth
import Config

#===============================================================================
# 'Vtap' is based on GAE Twitter API Proxy AKA 'Gtap' and 
# runs on non-GAE platform, typically on Virtual Private Server w/ apache.
# 
# Ported from GAE by fatal1tyv
# @fatal1tyv on twitter
# http://www.fatal1tyv.com
#===============================================================================


Vtap_version = '3 Powered by Django 1.2.5'

Vtap_message = """
    <html>
        <head>
        <title>VPS API Proxy</title>
        <link href='https://appengine.google.com/favicon.ico' rel='shortcut icon' type='image/x-icon' />
        <style>body { padding: 20px 40px; font-family: Verdana, Helvetica, Sans-Serif; font-size: medium; }</style>
        </head>
        <body><h2>Vtap v#Vtap_version# is running!</h2></p>
        <p><a href='/oauth/session'>Sign in your Twitter and Grant OAuth</a> <br>
        <a href='/oauth/change'>change your key</a></p>
        <p>This is a django-powered python program which runs under Apache2 web server</p>
        <p><font color='red'><b>Don't forget the \"/\" at the end of your api proxy address!!!.</b></font></p>
    </body>
    
    </html>
    """
    
error_message = "Vtap Error"
if Config.ENABLE_LOGGING:
    mainLogger = logging.getLogger('gtap.main')
    mainLogger.setLevel(Config.LOGGING_LEVEL)
    handler = logging.FileHandler(Config.LOGGING_PATH, 'a')
    formatter = logging.Formatter(Config.LOGGING_FORMAT)
    handler.setFormatter(formatter)
    mainLogger.addHandler(handler)

def success_output(content):

    response = HttpResponse(content='', mimetype='text/html', status=200, content_type='text/html')
    response['Vtap-Version'] = Vtap_version
    response._set_content(content)
    return response
    

def error_output(content):
  
    response = HttpResponse(content='', mimetype='text/html', status=503, content_type='text/html')
    response['Vtap-Version'] = Vtap_version
    response._set_content(content)
    return response
    
#class MainPage(webapp):
class MainPage():
    
    
    def conver_url(self, orig_url):
        mainLogger.debug("conver_url()")
        
        (scm, netloc, path, params, query, _) = urlparse.urlparse(orig_url)
        path_parts = path.split('/')
        
        if path_parts[1] == 'api' or path_parts[1] == 'search':
            sub_head = path_parts[1]
            path_parts = path_parts[2:]
            path_parts.insert(0, '')
            new_path = '/'.join(path_parts).replace('//', '/')
            new_netloc = sub_head + '.twitter.com'
        else:
            new_path = path
            new_netloc = 'twitter.com'
    
        new_url = urlparse.urlunparse(('https', new_netloc, new_path.replace('//', '/'), params, query, ''))
        
        return new_url, new_path

    def parse_auth_header(self, headers):
        mainLogger.debug("parse_auth_header()")

        username = None
        password = None
        
        
        if 'HTTP_AUTHORIZATION' in headers :
            auth_header = headers['HTTP_AUTHORIZATION']
            auth_parts = auth_header.split(' ')
            user_pass_parts = base64.b64decode(auth_parts[1]).split(':')
            username = user_pass_parts[0]
            password = user_pass_parts[1]
    
        return username, password

    def do_proxy(self, request):
        mainLogger.debug("do_proxy()")
        #prepare response
        response = HttpResponse()
        
        orig_url = request.build_absolute_uri()  # This appears to be correct
        orig_paralist = request.REQUEST.items()
        orig_body = {}
        
        for tp in orig_paralist:
            key = tp[0].encode('utf-8')
            value = tp[1].encode('utf-8')
            orig_body[key] = value #converts unicode para to plain str
       
        if request.method != 'GET' and request.method != 'POST':
            raw = urlparse.parse_qs(request.raw_post_data)
            for key in raw:
                orig_body[key] = str(raw.get(key)[0])                
    
        new_url, new_path = self.conver_url(orig_url)

        if new_path == '/' or new_path == '':
            global Vtap_message
            Vtap_message = Vtap_message.replace('#Vtap_version#', Vtap_version)
            mainLogger.debug("MainPaged loaded successfully")
            return success_output(Vtap_message)
        
        username, password = self.parse_auth_header(request.META)    #request.META includes header infos     
        user_access_token = None
        
        callback_url = "%soauth/verify" % Config.API_BASE_URL
        client = oauth.TwitterClient(Config.CONSUMER_KEY, Config.CONSUMER_SECRET, callback_url)
        
       
        if username is None :  
            protected = False
            user_access_token, user_access_secret = '', ''
        else:
            protected = True
            user_access_token, user_access_secret = client.get_access_from_db(username, password)
            if user_access_token is None :
                mainLogger.error('Can not find this user from db')
                return error_output('Can not find this user from db')
        
        use_method = 'GET' if request.method == 'GET' else 'POST'

        try :
            data = client.make_request(url=new_url, token=user_access_token, secret=user_access_secret,
                                   method=use_method, protected=protected,
                                   additional_params=orig_body)
            #try to return response from here
            
            response = success_output(data)
            return response
        
        
        except Exception, error_message :
            mainLogger.error(str(request))
            error_output(error_message)
            
class OauthPage():
    
    def get(self, request, mode=""): 
        mainLogger.debug("get()")
        
        callback_url = "%soauth/verify" % Config.API_BASE_URL
        client = oauth.TwitterClient(Config.CONSUMER_KEY, Config.CONSUMER_SECRET, callback_url)

        if mode == 'session':
            mainLogger.debug('session')
            # step C Consumer Direct User to Service Provider
            try:
                
                auth_url = client.get_authorization_url() # passed this step
                response = HttpResponseRedirect(auth_url) # redirect good and generates correct callback
                return response
            
            except Exception, error_message:
                mainLogger.error(str(request))
                return error_output(error_message)


        if mode == 'verify':
            mainLogger.debug('verify')
            # step D Service Provider Directs User to Consumer
            auth_token = request.GET.get("oauth_token")
            auth_verifier = request.GET.get("oauth_verifier")

            # step E Consumer Request Access Token 
            # step F Service Provider Grants Access Token
            try:
                access_token, access_secret, screen_name = client.get_access_token(auth_token, auth_verifier)
                self_key = '%s' % uuid4()
                # Save the auth token and secret in our database.
                client.save_user_info_into_db(username=screen_name, password=self_key,
                                              token=access_token, secret=access_secret)
                
                show_key_url = '%soauth/showkey?name=%s&key=%s' % (Config.API_BASE_URL,
                                                                       screen_name, self_key)
                response = HttpResponseRedirect(show_key_url)
                return response
            
            except Exception, error_message:
                mainLogger.error(str(request))
                return error_output(error_message)
            
            
        if mode == 'showkey':
            mainLogger.debug("showkey")
            screen_name = request.GET.get("name")
            self_key = request.GET.get("key")
            out_message = """
                <html><head><title>Vtap</title>
                <style>body { padding: 20px 40px; font-family: Courier New; font-size: medium; }</style>
                </head><body><p>
                your twitter's screen name : <b>#screen_name#</b> <br /><br />
                the Key of this API : <b>#self_key#</b> <a href="#api_host#oauth/change?name=#screen_name#&key=#self_key#">you can change it now</a><br /><br />
                </p>
                <p>
                In the third-party client of Twitter which support Custom API address,<br />
                set the API address as <b>#api_host#/</b> or <b>http://#api_host#api/1/</b> , <br />
                and set Search API address as <b>#api_host#search/</b> . <br />
                Then you must use the <b>Key</b> as your password when Sign-In in these clients.
                </p></body></html>
                """
            out_message = out_message.replace('#api_host#', Config.API_BASE_URL)
            out_message = out_message.replace('#screen_name#', screen_name)
            out_message = out_message.replace('#self_key#', self_key)
            return success_output(out_message)
        
        if mode == 'change':
            mainLogger.debug("changekey")
            screen_name = request.GET.get("name")
            self_key = request.GET.get("key")
            out_message = """
                <html><head><title>Vtap</title>
                <style>body { padding: 20px 40px; font-family: Courier New; font-size: medium; }</style>
                </head><body><p><form method="post" action="%soauth/changekey">
                your screen name of Twitter : <input type="text" name="name" size="20" value="%s"> <br /><br />
                your old key of this API : <input type="text" name="old_key" size="50" value="%s"> <br /><br />
                define your new key of this API : <input type="text" name="new_key" size="50" value=""> <br /><br />
                <input type="submit" name="_submit" value="Change the Key">
                </form></p></body></html>
                """ % (Config.API_BASE_URL, screen_name, self_key)
            return success_output(out_message)
            
    def post(self, request, mode=''):
        mainLogger.debug("post()");

        callback_url = "%soauth/verify" % Config.API_BASE_URL
        client = oauth.TwitterClient(Config.CONSUMER_KEY, Config.CONSUMER_SECRET, callback_url)
        
        if mode == 'changekey':
            mainLogger.debug("changekey");
            screen_name = request.POST.get("name")
            old_key = request.POST.get("old_key")
            new_key = request.POST.get("new_key")
            user_access_token, user_access_secret = client.get_access_from_db(screen_name, old_key)
            
            if user_access_token is None or user_access_secret is None:
                mainLogger.error('Can not find user from db, or invalid old_key.')
                return error_output('Can not find user from db, or invalid old_key.')
                
            else:
                try:
                    userName = str(screen_name)
                    password = str(new_key)
                    
                    client.save_user_info_into_db(userName, password, user_access_token, user_access_secret)
                    show_key_url = '%soauth/showkey?name=%s&key=%s' % (Config.API_BASE_URL,
                                                                        screen_name, new_key)
                    response = HttpResponseRedirect(show_key_url)
                    return response
                
                except Exception, error_message:
                    mainLogger.error(str(request))
                    return error_output(error_message)

